from nodes import *
# get node list


def revert_dict(src):
    dest = {}
    for key in src:
        dest[src[key]] = key
    return dest

LEFT_BRACKETS = {
    '{{': '}}',
    '{#': '#}',
    '{%': '%}',
}

RIGHT_BRACKETS = revert_dict(LEFT_BRACKETS)

SHADOW = {
    '\'': '\'',
    '\"': '\"',
}


def build_node(src):
    node = None
    src = str(src)
    # build value node
    if src[0:2] == '{{':
        node = ValNode(src=src)
    # build comment node
    if src[0:2] == '{#':
        node = CommentNode(src=src)
    # build wrapper node
    i = 0
    while i < len(src):
        if src[i:i+2] == 'if':
            if src[i:i+7] == 'ifequal':
                node = IfEqualNode(src=src)
                break
            elif src[i:i+10] == 'ifnotequal':
                node = IfNotEqualNode(src=src)
                break
            else:
                node = IfNode(src=src)
                break
        elif src[i:i+4] == 'else':
            node = ElseNode(src=src)
            break
        elif src[i:i+4] == 'elif':
            node = ElifNode(src=src)
            break
        elif src[i:i+3] == 'for':
            node = ForNode(src=src)
            break
        elif src[i:i+5] == 'while':
            node = WhileNode(src=src)
            break
        elif src[i:i+3] == 'end':
            node = EndNode(src=src)
            break
        elif src[i:i + 7] == 'include':
            node = IncludeNode(src=src)
            break
        elif src[i:i + 5] == 'block':
            node = BlockNode(src=src)
            break
        elif src[i:i + 7] == 'extends':
            node = ExtendsNode(src=src)
            break
        i += 1
    return node


def build_text_node(src):
    src = str(src)
    return TextNode(src=src)


def is_escape_char(src, index):
    # is_escape_char("\n", 1), ("a\n", 2), ("\\")
    escape = 0
    i = 0
    while i < len(src):
        if i == index:  # check str before index
            break
        if src[i] == '\\':
            escape += 1
        i += 1
    if escape % 2 == 1:
        return True
    return False


def get_node_list(src):
    node_list = []
    include_list = []  # (node, index)
    last_end = -1  # if start with no-text node, will not build text node
    shadowed = False
    last_shadow = ''
    last_bracket_location = -1  # start index
    last_barcket = ''
    # loop
    i = 0
    while i < len(src):
        # todo: escape character
        # check shadowed
        if (src[i] in SHADOW) and (not is_escape_char(src, i)):
            if not shadowed:
                shadowed = True
                last_shadow = src[i]
            else:
                if src[i] == SHADOW[last_shadow]:
                    shadowed = False
                    last_shadow = ''
                else:
                    raise RuntimeError('ERROR_BRACKETS_NO_MATCH')  # '"', "'" is illegal
        # check left bracket
        if (src[i: i+2] in LEFT_BRACKETS) and (not shadowed):
            # build text node
            if i > last_end + 1:
                node = build_text_node(src[last_end+1:i])
                node_list.append(node)
            last_barcket = src[i: i+2]
            last_bracket_location = i
            i += 1  # skip known char
        # check right bracket
        if (src[i: i+2] in RIGHT_BRACKETS) and (not shadowed):
            if not src[i: i+2] == LEFT_BRACKETS[last_barcket]:
                raise RuntimeError('ERROR_BRACKETS_NO_MATCH')
            node = build_node(src[last_bracket_location:i+2])
            node_list.append(node)
            if node.tag in {'IncludeNode', 'ExtendsNode', 'BlockNode'}:
                include_list.append([node, len(node_list) - 1])
            last_bracket_location = -1
            last_barcket = ''
            last_end = i + 1
            i += 1  # skip known char
        i += 1
    # build last text node
    if last_end < len(src):
        node = build_text_node(src[last_end + 1:])
        node_list.append(node)
    return node_list, include_list


# get node tree

WRAPPER = {
    'IfNode',
    'IfEqualNode',
    'IfNotEqualNode',
    'ForNode',
    'WhileNode',
    'BlockNode',
    'ExtendsNode'
}

SINGLE = {
    'ValNode',
    'TextNode',
    'ElseNode',
    'ElifNode',
    'IncludeNode',
}


def get_node_tree(node_list):
    # build node tree, without EndNode, CommentNode
    root = RootNode()
    extends_list = []
    wrapper_nodes = [[root, 0], ]  # build stack, append node
    # loop
    i = 0
    while i < len(node_list):
        node = node_list[i]
        # skip comment
        if node.tag == 'CommentNode':
            i += 1
            continue
        # is wrapper node
        if node.tag in WRAPPER:
            wrapper_nodes.append([node, i])
        # is single node
        if node.tag in SINGLE:
            # get top of the stack
            wrapper = wrapper_nodes[-1][0]
            # add node to top's child nodes
            wrapper.child_nodes.append(node)
        # is end node
        if node.tag == 'EndNode':
            # get top, pop
            tmp = wrapper_nodes.pop(-1)[0]
            if tmp.tag in {'ExtendsNode'}:
                extends_list.append(tmp)
            wrapper = wrapper_nodes[-1][0]
            # add node to top's child nodes
            wrapper.child_nodes.append(tmp)
        i += 1
    return root, extends_list



